﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Orchard.ContentManagement;
using Orchard.Localization.Models;
using Orchard.Localization.Services;

namespace Vitus.Localization.Helpers
{
    public static class LocalizationHelper
    {
        /// <summary>
        /// Gets the property value of the master content item part.
        /// </summary>
        /// <typeparam name="TPart">The type of the content part.</typeparam>
        /// <typeparam name="TProp">The type of the property.</typeparam>
        /// <param name="part">The content part.</param>
        /// <param name="property">The property.</param>
        /// <returns>The master content item property value.</returns>
        public static TProp GetMasterValue<TPart, TProp>(
            TPart part,
            Expression<Func<TPart, TProp>> property)
            where TPart : ContentPart, new()
        {
            var memberExpression = property.Body as MemberExpression;
            PropertyInfo prop = memberExpression.Member as PropertyInfo;

            return (TProp)prop.GetValue(part.GetMasterContentItem().As<TPart>(), null);
        }

        // Ty parametry updater a prefix jsou asi k ničemu...
        public static void UpdateLocalizations<P>(
            P part,
            IUpdateModel updater,
            ILocalizationService localizationService,
            string prefix,
            params string[] propNames)
            where P : ContentPart, new()
        {
            if (part.ContentItem.Has<LocalizationPart>())
            {
                var localizedParts = localizationService
                    .GetLocalizations(part.ContentItem, VersionOptions.AllVersions)
                    .Except(new[] { part.As<LocalizationPart>() })
                    .Select(loc => loc.As<P>());

                foreach (var locPart in localizedParts)
                {
                    foreach (var propName in propNames)
                    {
                        var prop = typeof(P).GetProperty(propName);
                        prop.SetValue(locPart, prop.GetValue(part, null), null);
                    }

                    updater.TryUpdateModel(locPart, prefix, propNames, null);
                }
            }
        }

        /// <summary>
        /// Updates all localizations of the specified content, including master content item.
        /// </summary>
        /// <typeparam name="TContent">The content type.</typeparam>
        /// <param name="content">The content.</param>
        /// <param name="localizationService">The localization service.</param>
        /// <param name="properties">The properties to be updated.</param>
        public static void UpdateLocalizations<TContent>(
            TContent content,
            ILocalizationService localizationService,
            params Expression<Func<TContent, object>>[] properties)
            where TContent : IContent, new()
        {
            if (content.ContentItem.Has<LocalizationPart>())
            {
                var localizations = localizationService
                    .GetLocalizations(content.ContentItem, VersionOptions.AllVersions)
                    .Union(new[] { content.GetMasterContentItem().As<LocalizationPart>() })
                    .Except(new[] { content.As<LocalizationPart>() })
                    .Select(loc => loc.As<TContent>());

                foreach (var localization in localizations)
                {
                    foreach (var expression in properties)
                    {
                        var memberExpression = expression.Body as MemberExpression;
                        PropertyInfo prop = memberExpression.Member as PropertyInfo;
                        prop.SetValue(localization, prop.GetValue(content, null), null);
                    }
                }
            }
        }

        /// <summary>
        /// Gets the master content item even if the content item is master itself.
        /// </summary>
        /// <param name="content">The content with a localization part.</param>
        /// <returns>The master content item.</returns>
        public static IContent GetMasterContentItem(this IContent content)
        {
            if (content == null || !content.Has<LocalizationPart>())
            {
                return null;
            }

            var locPart = content.As<LocalizationPart>();

            return locPart.MasterContentItem != null ? locPart.MasterContentItem : content.ContentItem;
        }
    }
}